package com.ray.controller.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.ray.interceptor.base.AopContext;
import com.ray.interceptor.base.BizInterceptConfig;
import com.ray.interceptor.base.MetaObjectIntercept;
import com.ray.log.WebLog;
import com.ray.model.DataButton;
import com.ray.model.DataField;
import com.ray.model.DataObject;
import com.ray.services.TemplateService;
import com.ray.util.Commen;
import com.ray.util.Ret;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Raytable 各模板数据处理公共类
 */
@RestController
@RequestMapping("template")
public class TemplateController extends BaseController {

    @Autowired
    private BizInterceptConfig bizInterceptConfig;

    @Autowired
    protected MetaObjectIntercept intercept;

    @Autowired
    private TemplateService templateService;

    /**
     * @note 根据元数据对象获取数据库字段表头
     * @time 2024年03月24日 19:31:56
     * @author Ray
     */
    @RequestMapping("getColumns")
    @WebLog(description = "根据元数据对象获取数据库字段表头")
    public Ret getColumns(String data_object_no) throws Exception {
        DataObject model = dataObjectService.getDataObject(data_object_no);
        List<DataField> list = dataObjectService.getDataFields(data_object_no);
        // 是否显示查询按钮
        boolean is_query = false;
        // 获取select radio控件的数据集
        Record selectDatas = new Record();
        Record validator = new Record();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getIsQuery()) {
                is_query = true;
            }
            List<Record> temp = new ArrayList<Record>();
            if ("select".equals(list.get(i).getType()) || "radio".equals(list.get(i).getType())
                    || "checkbox".equals(list.get(i).getType())) {
                String sql = "select " + list.get(i).getTypeConfig().split("\\|")[1] + " as label,"
                        + list.get(i).getTypeConfig().split("\\|")[2] + " as value "
                        + list.get(i).getTypeConfig().split("\\|")[0];
                /**
                 * query before
                 */
                intercept = bizInterceptConfig.initMetaObjectIntercept(model.getInterceptor());
                if (intercept != null) {
                    AopContext ac = new AopContext(user(), list.get(i).getEn());
                    ac.sql = sql;
                    sql = intercept.fieldQueryBefore(ac);
                }
                //region,userid模板
                sql = sql.replaceAll("#region", getSessionUserRegion())
                        .replaceAll("#userid", getSessionUserId())
                        .replaceAll("#datasource_main", main)
                        .replaceAll("#datasource_base", base);
                temp = dbService.getSelectRadioCheckboxList(sql);
                if (!temp.isEmpty()) {
                    selectDatas.set(list.get(i).getEn(), temp);
                }
            }
            // 获取字段前端校验
            JSONArray JA = JSONArray.parseArray(list.get(i).getValidator());
            validator.set(list.get(i).getEn(), JA);
        }
        // 获取头部buttons
        List<DataButton> headButtons = dataObjectService.getDataButtons(data_object_no, 1);
        // 获取行内buttons
        List<DataButton> lineButtons = dataObjectService.getDataButtons(data_object_no, 2);
        // 获取右键buttons
        List<DataButton> rightButtons = dataObjectService.getDataButtons(data_object_no, 3);
        return Ret.ok("msg", "成功")
                .setJson("list", list)
                .setJson("headButtons", headButtons)
                .setJson("lineButtons", lineButtons)
                .setJson("rightButtons", rightButtons)
                .setJson("selectDatas", selectDatas)
                .setJson("validator", validator)
                .setJson("data_object", model)
                .set("is_query", is_query);
    }

    /**
     * @note 获取表数据
     * @time 2024年03月24日 19:55:18
     * @author Ray
     */
    @RequestMapping("getData")
    @WebLog(description = "获取表数据")
    public Ret getData(String data_object_no, String queryForm, int currentPage, int pageSize) throws Exception {
        DataObject model = dataObjectService.getDataObject(data_object_no);
        List<DataField> fields = dataObjectService.getDataFields(data_object_no);
        String sqlString = dbService.sqlFormat(model.getTableName(), fields, queryForm, getSessionUserRegion(), base);
        /**
         * query before
         */
        intercept = bizInterceptConfig.initMetaObjectIntercept(model.getInterceptor());
        if (intercept != null) {
            AopContext ac = new AopContext(user());
            ac.sql = sqlString;
            sqlString = intercept.queryBefore(ac);
        }
        sqlString += model.getWhereAttr() != null ? model.getWhereAttr() : "";
        //region,userid模板
        sqlString = sqlString.replaceAll("#region", getSessionUserRegion())
                .replaceAll("#userid", getSessionUserId())
                .replaceAll("#datasource_base", base)
                .replaceAll("#datasource_main", main);
        SqlPara sql = new SqlPara();
        sql.setSql(sqlString);
        List<Record> resData = new ArrayList<>();
        int totalRow = 0;
        if (model.getIsPage()) {
            Page<Record> list = dbService.paginate(model.getDataSource(), model.getTableName(), sql, currentPage, pageSize, true);
            totalRow = list.getTotalRow();
            resData = list.getList();
        } else {
            resData = dbService.find(model.getDataSource(), model.getTableName(), sql.getSql(), true);
        }
        /**
         * query after
         */
        AopContext ac = new AopContext(user(), resData);
        intercept = bizInterceptConfig.initMetaObjectIntercept(model.getInterceptor());
        if (intercept != null) {
            ac.object = model;
            intercept.queryAfter(ac);
        }
        return Ret.ok("成功").setJson("list", resData).set("totalResult", totalRow).set("mergeCells", ac.mergeCells);
    }

    /**
     * @note 新增数据
     * @time 2024年03月24日 20:21:22
     * @author Ray
     */
    @RequestMapping("new_")
    @WebLog(description = "新增数据")
    public Ret new_(@RequestBody JSONObject param) throws Exception {
        String data_object_no = param.getString("data_object_no");
        DataObject object = dataObjectService.getDataObject(data_object_no);
        Map map = JSON.parseObject(param.getJSONObject("form").toJSONString(), Map.class);
        Record model = new Record().setColumns(map);

        //处理多选下拉框传值问题
        List<DataField> fields = dataObjectService.getDataFields(object.getNo());
        for (int i = 0; i < fields.size(); i++) {
            if ("selector".equals(fields.get(i).getType()) || "user".equals(fields.get(i).getType())) {
                model.remove(fields.get(i).getEn() + "_show_value");
            }
        }

        /**
         * 上下文
         */
        AopContext ac = new AopContext(user(), model, map, param.getBoolean("interceptorConfirm"));
        ac.object = object;
        ac.parent = JSONObject.parseObject(param.getString("parent"));
        intercept = bizInterceptConfig.initMetaObjectIntercept(object.getInterceptor());

        //如果拦截器不为空
        if (intercept != null) {
            //add before
            Ret res = intercept.addBefore(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
            //add and add after
            templateService.addAndAddafter(object, model, intercept, ac);
            //add succeed
            res = intercept.addSucceed(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
        } else {
            dbService.save(object.getDataSource(), object.getTableName(), model);
        }
        Record newData = Db.use(object.getDataSource()).findFirst(dbService.sqlFormatUpdate(object.getTableName(), fields, model.get("id"), getSessionUserRegion(), getSessionUserId(), base, main));
        return Ret.ok("msg", "新增成功").setJson("newData", newData);
    }

    /**
     * @note 修改数据
     * @time 2024年03月25日 09:24:03
     * @author Ray
     */
    @RequestMapping("edit_")
    @WebLog(description = "修改数据")
    public Ret edit_(@RequestBody JSONObject param) throws Exception {
        String data_object_no = param.getString("data_object_no");
        DataObject object = dataObjectService.getDataObject(data_object_no);
        Map map = JSON.parseObject(param.getJSONObject("row").toJSONString(), Map.class);
        Record temp = new Record().setColumns(map);
        Record model = new Record();
        List<Record> list = Db.use("sys")
                .find("select * from columns where table_schema = '" + object.getDataSource()
                        + "' and table_name = '" + object.getTableName() + "'"
                        + " and COLUMN_NAME not in ('region','is_delete','del_user_id','del_time') order by ORDINAL_POSITION");
        for (int i = 0; i < list.size(); i++) {
            model.set(list.get(i).getStr("COLUMN_NAME"), temp.get(list.get(i).getStr("COLUMN_NAME")));
        }

        /**
         * 上下文
         */
        AopContext ac = new AopContext(user(), model, map, param.getBoolean("interceptorConfirm"));
        ac.field = param.getString("column");
        ac.object = object;
        ac.parent = param.getJSONObject("parent");
        intercept = bizInterceptConfig.initMetaObjectIntercept(object.getInterceptor());

        //如果拦截器不为空
        if (intercept != null) {
            //update before
            Ret res = intercept.updateBefore(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
            //update and update after
            templateService.updateAndUpdateafter(object, model, intercept, ac);
            //update succeed
            res = intercept.updateSucceed(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
        } else {
            dbService.update(object.getDataSource(), object.getTableName(), model);
        }
        Record updateData = Db.use(object.getDataSource()).findFirst(dbService.sqlFormatUpdate(object.getTableName(), dataObjectService.getDataFields(object.getNo()), model.get("id"), getSessionUserRegion(), getSessionUserId(), base, main));
        return Ret.ok("msg", "修改成功").setJson("updateData", updateData);
    }

    /**
     * @note 删除数据
     * @time 2024年03月25日 09:33:34
     * @author Ray
     */
    @RequestMapping("del_")
    @WebLog(description = "删除数据")
    public Ret del_(String data_object_no, int id) throws Exception {
        DataObject object = dataObjectService.getDataObject(data_object_no);
        /**
         * 上下文
         */
        Record model = Db.use(object.getDataSource()).findById(object.getTableName(), id);
        AopContext ac = new AopContext(user(), model);
        ac.object = object;
        intercept = bizInterceptConfig.initMetaObjectIntercept(object.getInterceptor());

        //如果拦截器不为空
        if (intercept != null) {
            //update before
            Ret res = intercept.deleteBefore(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
            //update and update after
            templateService.deleteAndDeleteafter(object, model, intercept, ac);
            //update succeed
            res = intercept.deleteSucceed(ac);
            if (!Commen.isEmptyy(res)) {
                return res;
            }
        } else {
            dbService.delete(object.getDataSource(), object.getTableName(), model, getSessionUserId());
        }
        return Ret.ok("msg", "删除成功");
    }

    /**
     * @note 获取弹窗选择器控件数据
     * @time 2024年03月25日 09:56:53
     * @author Ray
     */
    @RequestMapping("getSelectorData")
    @WebLog(description = "获取弹窗选择器控件数据")
    public Ret getSelectorData(@RequestBody JSONObject param) {
        JSONObject config = param.getJSONObject("type_config");
        String sql = config.getString("sql");
        if (!sql.contains("where")) {
            sql += " where 1=1";
        }
        JSONObject search = param.getJSONObject("search");
        if (!search.isEmpty()) {
            JSONArray searchFields = config.getJSONArray("searchFields");
            for (int i = 0; i < searchFields.size(); i++) {
                JSONObject field = searchFields.getJSONObject(i);
                if (search.getString(field.getString("en")) != null && !"".equals(search.getString(field.getString("en")).trim()))
                    sql += " and " + field.getString("en") + " like '" + search.getString(field.getString("en")).trim() + "'";
            }
            JSONArray where = config.getJSONArray("where");
            if (where != null) {
                for (int i = 0; i < where.size(); i++) {
                    JSONObject field = where.getJSONObject(i);
                    if (search.getString(field.getString("key")) != null)
                        sql += " and " + field.getString("key") + " = '" + search.getString(field.getString("key")) + "'";
                }
            }
            JSONArray form_where = config.getJSONArray("form_where");
            if (form_where != null) {
                for (int i = 0; i < form_where.size(); i++) {
                    JSONObject field = form_where.getJSONObject(i);
                    if (search.getString(field.getString("key")) != null) {
                        sql = sql + " and " + field.getString("key") + " = '" + search.getString(field.getString("key")) + "'";
                    }
                }
            }
        }
        //region,userid模板
        sql = sql.replaceAll("#region", getSessionUserRegion())
                .replaceAll("#userid", getSessionUserId())
                .replaceAll("#datasource_main", main)
                .replaceAll("#datasource_base", base);
        SqlPara sqlPara = new SqlPara().setSql(sql);
        Page<Record> page = Db.paginate(param.getInteger("currentPage"), param.getInteger("pageSize"), sqlPara);
        return Ret.ok("msg", "成功").setJson("page", page);
    }

    /**
     * @note 树形单表模板获取树形结构数据
     * @time 2024年03月26日 12:57:35
     * @author Ray
     */
    @RequestMapping("getTree")
    @WebLog(description = "树形单表模板获取树形结构数据")
    public Ret getTree(String data_object_no, String tree_parent_no, String tree_no, String tree_field) throws Exception {
        DataObject model = dataObjectService.getDataObject(data_object_no);
        String sqlString = "select *," + tree_field + " as label from " + model.getTableName() + " where 1=1 ";
        intercept = bizInterceptConfig.initMetaObjectIntercept(model.getInterceptor());
        if (intercept != null) {
            AopContext ac = new AopContext(user());
            ac.sql = sqlString;
            sqlString = intercept.queryBefore(ac);
        }
        sqlString += model.getWhereAttr() != null ? model.getWhereAttr() : "";
        //region,userid模板
        sqlString = sqlString.replaceAll("#region", getSessionUserRegion())
                .replaceAll("#userid", getSessionUserId())
                .replaceAll("#datasource_main", main)
                .replaceAll("#datasource_base", base);
        List<Record> list = dbService.find(model.getDataSource(), model.getTableName(), sqlString + " and " + tree_parent_no + " = '0' ", true);
        list = tree(list, model.getDataSource(), sqlString, tree_parent_no, tree_no);
        return Ret.ok("msg", "成功").setJson("tree", list);
    }

    public static List<Record> tree(List<Record> trees, String datasource, String sqlString, String tree_parent_no, String tree_no) {
        for (int i = 0; i < trees.size(); i++) {
            String sql = sqlString + " and " + tree_parent_no + " = '" + trees.get(i).getStr(tree_no) + "'";
            List<Record> temp = Db.use(datasource).find(sql);
            trees.get(i).set("children", tree(temp, datasource, sqlString, tree_parent_no, tree_no));
        }
        return trees;
    }
}
